#include <speed.h>

#if defined(__x86_64__) || defined(_M_X64)

#include <cpuid.h>
#include <stdio.h>

#define SS_SSE  (1<<0)
#define SS_SSE2 (1<<1)
#define SS_SSE3 (1<<2)
#define SS_SSE4 (1<<3)
#define SS_SSSE3 (1<<4)
#define SS_SSE4A (1<<5)
#define SS_SSE41 (1<<6)
#define SS_SSE42 (1<<7)
#define SS_AVX (1<<8)
#define SS_AVX2 (1<<9)
#define SS_AVX512F (1<<10)
#define SS_AVX512DQ (1<<11)
#define SS_AVX512IFMA (1<<12)
#define SS_AVX512PF (1<<13)
#define SS_AVX512ER (1<<14)
#define SS_AVX512CD (1<<15)
#define SS_AVX512BW (1<<16)
#define SS_AVX512VL (1<<17)
#define SS_AVX512VBMI (1<<18)
#define SS_AVX512VBMI2 (1<<19)
#define SS_AVX512VNNI (1<<20)
#define SS_AVX512BITALG (1<<21)
#define SS_AVX512VPOPCNTDQ (1<<22)
#define SS_AVX512_4VNNIW (1<<23)
#define SS_AVX512_4FMAPS (1<<24)
#define SS_AVX512_4BITALG (1<<25)

static int flags;

void init_speed(void){
    unsigned int eax, ebx, ecx, edx;
    __get_cpuid(1, &eax, &ebx, &ecx, &edx);
    if(edx & bit_SSE) flags |= SS_SSE;
    if(edx & bit_SSE2) flags |= SS_SSE2;
    if(ecx & bit_SSE3) flags |= SS_SSE3;
    if(ecx & bit_SSSE3) flags |= SS_SSSE3;
    if(ecx & bit_SSE4_1) flags |= SS_SSE41;
    if(ecx & bit_SSE4_2) flags |= SS_SSE42;
    if(ecx & bit_AVX) flags |= SS_AVX;
    eax = 7, ecx = 0;
    __get_cpuid(1, &eax, &ebx, &ecx, &edx);
    if(ecx & bit_SSE4a) flags |= SS_SSE4A;
    if(ebx & bit_AVX2) flags |= SS_AVX2;
    if(ebx & bit_AVX512F) flags |= SS_AVX512F;
    if(ebx & bit_AVX512DQ) flags |= SS_AVX512DQ;
    if(ebx & bit_AVX512IFMA) flags |= SS_AVX512IFMA;
    if(ebx & bit_AVX512PF) flags |= SS_AVX512PF;
    if(ebx & bit_AVX512ER) flags |= SS_AVX512ER;
    if(ebx & bit_AVX512CD) flags |= SS_AVX512CD;
    if(ebx & bit_AVX512BW) flags |= SS_AVX512BW;
    if(ebx & bit_AVX512VL) flags |= SS_AVX512VL;
    if(ecx & bit_AVX512VBMI) flags |= SS_AVX512VBMI;
    if(ecx & bit_AVX512VBMI2) flags |= SS_AVX512VBMI2;
    if(ecx & bit_AVX512VNNI) flags |= SS_AVX512VNNI;
    if(ecx & bit_AVX512BITALG) flags |= SS_AVX512BITALG;
    if(ecx & bit_AVX512VPOPCNTDQ) flags |= SS_AVX512VPOPCNTDQ;
    if(edx & bit_AVX5124VNNIW) flags |= SS_AVX512_4VNNIW;
    if(edx & bit_AVX5124FMAPS) flags |= SS_AVX512_4FMAPS;
    printf("flags: %016X\n", flags);
}

// __attribute__((sysv_abi)) extern void *memset_long(void *dest, const void *src, size_t len);
// __attribute__((sysv_abi)) extern void *memset_see(void *dest, const void *src, size_t len);
// __attribute__((sysv_abi)) extern void *memset_see_long(void *dest, const void *src, size_t len);
// __attribute__((sysv_abi)) extern void *memset_avx2(void *dest, const void *src, size_t len);

void *memset_ss(void *dest, int val, size_t len){
    return (void*)((size_t)dest + len + val);
}

#endif
